package ie.dpsystems.webservice;


import ie.dpsystems.json.JsonWrapper;

import java.io.IOException;
import java.util.ArrayList;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;


public  class SimpleNETWebServiceConnector {

	
	private static String _webServiceError="WebServiceError";
	private static String _webServiceErrorType="ErrorType";
	private static String _namespace="http://tempuri.org/";
	

	public static Integer GetInteger(Object value){
		SoapPrimitive primitive=(SoapPrimitive)value;
		return Integer.parseInt(primitive.toString());
	}
	public static Long GetLong(Object value){
		SoapPrimitive primitive=(SoapPrimitive)value;
		return Long.parseLong(primitive.toString());
	}
	public static HttpTransportSE GetNewTransportLayer(String endpointUrl)
	{
		HttpTransportSE htse = new HttpTransportSE(endpointUrl,600000);
		return htse;
	}
	public static void DisconnectTransportLayer(HttpTransportSE htse) throws IOException{
		if (htse!=null)
		{
		htse.getServiceConnection().disconnect();
		}
	}
	public static WSListResult  ExecuteMethodWithListResult(String endpointUrl,String methodName,ArrayList<WSParam> arguments) throws Throwable{
		
		WSListResult result=new WSListResult();
		HttpTransportSE htse =GetNewTransportLayer(endpointUrl);
		ArrayList<WSParam> wsResult=ExecuteMethodRetryingAndCheckForServerExceptions(htse,methodName,arguments);
		DisconnectTransportLayer(htse);
		SoapObject  innerListObject=null;
		for (WSParam res : wsResult){
			
			if (AreErrorControlParameter(res)){
				continue;
			}
			innerListObject=(SoapObject)res.getValue();
		}
					
        for(int i = 0;i<innerListObject.getPropertyCount();i++){
        	SoapObject innerObject=(SoapObject)innerListObject.getProperty(i);
        	ArrayList<WSParam> wsObject=new  ArrayList<WSParam>();
        	 for(int j = 0;j<innerObject.getPropertyCount();j++){
             	PropertyInfo pi = new PropertyInfo();
             	innerObject.getPropertyInfo(j, pi);
	        	wsObject.add(new WSParam(pi.getName(),pi.getValue()));
        	 }
        	 result.resultList.add(wsObject);
        	
        }
		return result;
		
	}
	private static void CheckForServerExceptions(ArrayList<WSParam> serverResult) throws WebServiceException{		
		int errorType=ErrorTypeEnum.UnHandled.value();
		String errorMessage=null;
		for (WSParam res : serverResult){
			
			if (res.getArgumentName().equals(_webServiceError)){
				errorMessage=res.getValue().toString();
			}
			if (res.getArgumentName().equals(_webServiceErrorType)){
				errorType=Integer.parseInt(res.getValue().toString());
			}
			
		}
		if (errorMessage==null || errorMessage==""){
			return;
		}
		throw new WebServiceException(ErrorTypeEnum.fromValue(errorType),errorMessage);
	}
	public static WSSingleResult  ExecuteMethodWithSingleResult(String endpointUrl,String methodName,ArrayList<WSParam> arguments) throws Throwable{
		
		WSSingleResult result=new WSSingleResult();
		HttpTransportSE htse =GetNewTransportLayer(endpointUrl);
		ArrayList<WSParam> wsResult=ExecuteMethodRetryingAndCheckForServerExceptions(htse,methodName,arguments);
		DisconnectTransportLayer(htse);
		for (WSParam res : wsResult){
			
			if (AreErrorControlParameter(res)){
				continue;
			}
			result.result=res;
		}
		return result;
		
	}
	private static String ExecuteJsonRequest(String endpointUrl,String methodName, String jsonParameters) throws Throwable{	
		ArrayList<WSParam> arguments=new ArrayList<WSParam>();
		arguments.add(new WSParam("jsonParameters",jsonParameters));
		WSSingleResult result=ExecuteMethodWithSingleResult(endpointUrl,methodName,arguments);
		return result.result.getValue().toString();
	}
	
	
	public static  <U,V> U ExecuteJson(String endpointUrl,String methodName,Class<U> classOfU,V param)throws Throwable{
		String jsonResult=ExecuteJsonRequest(endpointUrl,methodName,JsonWrapper.ToJson(param));
		return JsonWrapper.FromJson(jsonResult, classOfU);
	}
	public static  <U> U ExecuteJson(String endpointUrl,String methodName,Class<U> classOfU)throws Throwable{
		String jsonResult=ExecuteJsonRequest(endpointUrl,methodName,null);
		return JsonWrapper.FromJson(jsonResult, classOfU);
	}

	
	private static Boolean AreErrorControlParameter(WSParam param){
		return (param.getArgumentName().equals(_webServiceError) || param.getArgumentName().equals(_webServiceErrorType) );
	}
	public static WSMultipleResult  ExecuteMethodWithMultipleResult(String endpointUrl,String methodName,ArrayList<WSParam> arguments) throws Throwable{
		
		WSMultipleResult result=new WSMultipleResult();
		HttpTransportSE htse =GetNewTransportLayer(endpointUrl);
		ArrayList<WSParam> wsResult=ExecuteMethodRetryingAndCheckForServerExceptions(htse,methodName,arguments);
		DisconnectTransportLayer(htse);
		for (WSParam res : wsResult){
			
			if (AreErrorControlParameter(res)){
				continue;
			}
			result.result.add(res);
		}
		return result;
		
	}
	public static WSMultipleResult  ExecuteMethodWithMultipleResultTransactional(HttpTransportSE htse,String methodName,ArrayList<WSParam> arguments) throws Throwable{
		
		WSMultipleResult result=new WSMultipleResult();
		ArrayList<WSParam> wsResult=ExecuteMethodRetryingAndCheckForServerExceptions(htse,methodName,arguments);		
		for (WSParam res : wsResult){
			
			if (AreErrorControlParameter(res)){
				continue;
			}
			result.result.add(res);
		}
		return result;
		
	}

	private static ArrayList<WSParam>  ExecuteMethodRetryingAndCheckForServerExceptions(HttpTransportSE htse,String methodName,ArrayList<WSParam> arguments) throws Throwable{
		ArrayList<WSParam> result=ExecuteMethodRetrying(htse,methodName,arguments,0);
		CheckForServerExceptions(result);
		return result;
	}
	
	private static ArrayList<WSParam>  ExecuteMethodRetrying(HttpTransportSE htse,String methodName,ArrayList<WSParam> arguments, int tries) throws Throwable{
		
		try {
			return ExecuteMethodImplementation(htse,methodName,arguments);
		} catch (Throwable e) {
			if (tries>3){
				throw new Throwable(e);
			}
			
			return ExecuteMethodRetrying(htse,methodName,arguments,tries+1);
		}
	}
	private static ArrayList<WSParam>  ExecuteMethodImplementation(HttpTransportSE htse,String methodName,ArrayList<WSParam> arguments) throws Throwable{
		
		SoapObject request = new SoapObject(_namespace, methodName);
		for (WSParam arg : arguments) {
			 request.addProperty(arg.getArgumentName(), arg.getValue());
		    }
		SoapSerializationEnvelope soapEnvelope = 
	            new SoapSerializationEnvelope(SoapEnvelope.VER11);
	        soapEnvelope.dotNet = true;
	        
	        soapEnvelope.setOutputSoapObject(request);
	          
	        System.setProperty("http.keepAlive", "false");
	        ArrayList<WSParam>  returnValues=new ArrayList<WSParam>();
	        htse.call(_namespace+ methodName,soapEnvelope);
	        SoapObject response = (SoapObject) soapEnvelope.getResponse();
	        int elementCount = response.getPropertyCount();
	        for(int i = 0;i<elementCount;i++){
	        	PropertyInfo pi = new PropertyInfo();
	        	response.getPropertyInfo(i, pi);
	        	returnValues.add(new WSParam(pi.getName(),pi.getValue()));
	        	
	        }
	        return returnValues;
	       
	}
	
	 
	

		
		
		
		
	
	
}
